package simulaco.business;

import gminet.infra.business.BusinessException;
import gminet.infra.business.BusinessObject;
import gminet.infra.db.Transaction;
import gminet.infra.db.TransactionException;
import gminet.infra.toolkit.DateToolkit;
import gminet.infra.toolkit.NumberToolkit;
import gminet.infra.toolkit.StringToolkit;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import simulaco.dao.ConcursoMateriaDAO;
import simulaco.dao.MateriaDAO;
import simulaco.dao.MateriaFilter;
import simulaco.dto.Materia;
import simulaco.dto.Situacao;

public class MateriaBusiness extends BusinessObject {

    private static List<Materia> CACHE_LIST_MATERIAS = null;
    private static List<Materia> CACHE_LIST_MATERIAS_ACTIVES = null;

    public static Materia findByPK(int materiaId) throws TransactionException {

        Materia materia = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            materia = findByPK(materiaId, conn);
        } finally {
            transaction.release();
        }
        return materia;
    }

    protected static Materia findByPK(int materiaId, Connection conn) throws TransactionException {

        return MateriaDAO.findByPK(materiaId, conn);
    }

    public static List<Materia> findAll() throws TransactionException {

        if (CACHE_LIST_MATERIAS == null || CACHE_LIST_MATERIAS.size() == 0) {
            List<Materia> materias = null;
            Transaction transaction = createTransaction();
            try {
                Connection conn = transaction.getConnection();
                materias = MateriaDAO.findAll(conn);
            } catch (TransactionException te) {
                transaction.rollback();
                throw te;
            } finally {
                transaction.release();
            }
            // CACHE
            if (CACHE_LIST_MATERIAS == null) {
                CACHE_LIST_MATERIAS = new ArrayList<Materia>();
            }
            CACHE_LIST_MATERIAS.addAll(materias);
        }
        return CACHE_LIST_MATERIAS;
    }

    public static List<Materia> findActives() throws TransactionException {

        if (CACHE_LIST_MATERIAS_ACTIVES == null || CACHE_LIST_MATERIAS_ACTIVES.size() == 0) {
            List<Materia> materias = null;
            Transaction transaction = createTransaction();
            try {
                Connection conn = transaction.getConnection();
                MateriaFilter filter = new MateriaFilter();
                filter.setCodigoSituacao(Situacao.HABILITADO.getCodigo());
                materias = MateriaDAO.findByFilter(filter, conn);
            } catch (TransactionException te) {
                transaction.rollback();
                throw te;
            } finally {
                transaction.release();
            }
            // CACHE
            if (CACHE_LIST_MATERIAS_ACTIVES == null) {
                CACHE_LIST_MATERIAS_ACTIVES = new ArrayList<Materia>();
            }
            CACHE_LIST_MATERIAS_ACTIVES.addAll(materias);
        }
        return CACHE_LIST_MATERIAS_ACTIVES;
    }

    public static List<Materia> findByConcurso(int codConcurso, Connection conn) throws TransactionException {

        List<Materia> materias = null;
        MateriaFilter filter = new MateriaFilter();
        filter.setCodigoConcurso(codConcurso);
        materias = MateriaDAO.findByFilter(filter, conn);
        return materias;
    }

    public static Materia insert(Materia materia) throws BusinessException, TransactionException {

        Materia newMateria = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            // MATERIA
            Date dataAtual = DateToolkit.getDate();
            int rangeId = createRangeId(materia.getNome());
            materia.setCodigo(MateriaDAO.getNextCodigo(conn, rangeId, rangeId + 1000));
            if (materia.getSituacao().getCodigo() == 0) {
                materia.setSituacao(Situacao.DESABILITADO);
            }
            materia.setDataCadastro(dataAtual);
            MateriaDAO.insert(materia, conn);
            // COMMIT
            transaction.commit();
            // RELEASE CACHE
            releaseCache();
            //
            newMateria = materia;
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
        return newMateria;
    }

    private static int createRangeId(String materiaName) {

        String strCodigo = "1";
        String caracter1 = materiaName.substring(0, 1).toUpperCase();
        String caracter2 = materiaName.length() > 1 ? materiaName.substring(1, 2).toUpperCase() : "A";
        int valor1 = Math.abs(caracter1.compareTo("A") + 1);
        if (StringToolkit.isDigit(caracter1)) {
            valor1 = 0;
        }
        int valor2 = Math.abs(caracter2.compareTo("A") / 3);
        if (StringToolkit.isDigit(caracter2)) {
            valor2 = 0;
        }
        strCodigo += NumberToolkit.getStringFromInt(Math.min(valor1, 99), 2);
        strCodigo += NumberToolkit.getStringFromInt(Math.min(valor2, 9), 1);
        strCodigo += "000";
        return Integer.parseInt(strCodigo);
    }

    public static void update(Materia materia) throws BusinessException, TransactionException {

        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            MateriaDAO.update(materia, conn);
            // COMMIT
            transaction.commit();
            // RELEASE CACHE
            releaseCache();
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
    }

    public static void updateStatus(Materia materia) throws BusinessException, TransactionException {

        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            Materia auxMateria = MateriaDAO.findByPK(materia.getCodigo(), conn);
            auxMateria.setSituacao(materia.getSituacao());
            MateriaDAO.update(auxMateria, conn);
            // COMMIT
            transaction.commit();
            // RELEASE CACHE
            releaseCache();
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
    }

    public static void delete(Materia materia) throws BusinessException, TransactionException {

        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            // VERIFICA SE TEM CONCURSO VINCULADOS
            if (ConcursoMateriaDAO.findByMateria(materia.getCodigo(), conn).size() > 0) {
                throw new BusinessException("Não é possivel excluir esta materia. Existem concursos vinculados.");
            } else {
                // EXCLUI A MATERIA
                MateriaDAO.delete(materia, conn);
                transaction.commit();
                // RELEASE CACHE
                releaseCache();
            }
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
    }

    private static void releaseCache() {

        // CACHE_LIST_ORGAOS
        if (CACHE_LIST_MATERIAS != null) {
            CACHE_LIST_MATERIAS.clear();
        }
        CACHE_LIST_MATERIAS = null;
        // CACHE_LIST_ORGAOS_ACTIVES
        if (CACHE_LIST_MATERIAS_ACTIVES != null) {
            CACHE_LIST_MATERIAS_ACTIVES.clear();
        }
        CACHE_LIST_MATERIAS_ACTIVES = null;
    }

}
